package com.cskaoyan.market.service.wx;

import com.cskaoyan.market.db.domain.*;
import com.cskaoyan.market.db.mapper.*;
import com.cskaoyan.market.vo.CartIndexVo;
import com.cskaoyan.market.vo.WxCartCheckoutVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class WxCartServiceImpl implements WxCartService {
    @Autowired
    MarketCartMapper marketCartMapper;

    @Autowired
    MarketCouponMapper marketCouponMapper;

    @Autowired
    MarketAddressMapper marketAddressMapper;

    @Autowired
    MarketGoodsMapper marketGoodsMapper;

    @Autowired
    MarketCouponUserMapper marketCouponUserMapper;

    @Autowired
    MarketGoodsProductMapper marketGoodsProductMapper;

    @Override
    public boolean update(Integer productId, Integer goodsId, Short number, Integer id) {
        MarketCart marketCart = new MarketCart();
        marketCart.setProductId(productId);
        marketCart.setGoodsId(goodsId);
        marketCart.setNumber(number);
        marketCart.setId(id);
        int i = marketCartMapper.updateByPrimaryKeySelective(marketCart);
        return i == 1;
    }

    @Override
    public CartIndexVo delete(List<Integer> productIds, Integer userId) {
        MarketCartExample marketCartExample = new MarketCartExample();
        MarketCartExample.Criteria criteria = marketCartExample.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andProductIdIn(productIds);
        marketCartMapper.deleteByExample(marketCartExample);
        return index(userId);
    }

    @Override
    public CartIndexVo check(List<Integer> productIds, Boolean checked, Integer userId) {
        for (Integer productId : productIds) {
            MarketCartExample marketCartExample = new MarketCartExample();
            marketCartExample.createCriteria().andProductIdEqualTo(productId).andLogicalDeleted(true);
            MarketCart marketCart = marketCartMapper.selectOneByExample(marketCartExample);
            marketCart.setChecked(checked);
            marketCartMapper.updateByPrimaryKey(marketCart);
        }
        return index(userId);
    }

    @Override
    public WxCartCheckoutVo checkout(Integer cartId, Integer addressId, Integer couponId, Integer userCouponId, Integer grouponRulesId, Integer userId) {
        List<MarketCart> marketCarts = new ArrayList<>();
        if (cartId == 0) {
            marketCarts = getMarketCarts(userId);
        } else {
            MarketCart marketCart = marketCartMapper.selectByPrimaryKey(cartId);
            marketCarts.add(marketCart);
        }
        List<MarketCart> checkedCarts = getCheckedCarts(marketCarts);
        WxCartCheckoutVo wxCartCheckoutVo = new WxCartCheckoutVo();
        wxCartCheckoutVo.setCheckedGoodsList(checkedCarts);
        wxCartCheckoutVo.setGrouponRulesId(grouponRulesId);
        BigDecimal goodsTotalPrice = calculateTotalAmount(checkedCarts);
        wxCartCheckoutVo.setGoodsTotalPrice(goodsTotalPrice);
        int freight = goodsTotalPrice.longValue() >= 88 ? 0 : 8;
        BigDecimal freightPrice = BigDecimal.valueOf(freight);
        wxCartCheckoutVo.setFreightPrice(freightPrice);
        wxCartCheckoutVo.setCartId(cartId);
        wxCartCheckoutVo.setGrouponPrice(new BigDecimal(0));
        BigDecimal totalPrice = goodsTotalPrice.add(freightPrice);
        wxCartCheckoutVo.setOrderTotalPrice(totalPrice);
        //判断优惠券状态，如果为couponId=-1，则查询可用的优惠券数量；如果大于0，则使用指定的优惠券
        BigDecimal couponPrice;
        if (couponId == -1) {
            wxCartCheckoutVo.setAvailableCouponLength(getMarketCouponUserList(userId, totalPrice).size());
            couponPrice = BigDecimal.valueOf(0);
            wxCartCheckoutVo.setCouponId(couponId);
            wxCartCheckoutVo.setUserCouponId(userCouponId);
        } else {
            wxCartCheckoutVo.setAvailableCouponLength(getMarketCouponUserList(userId, totalPrice).size());
            if (couponId == 0) {
                Map<String, Integer> map = getDefaultCouponId(userId, totalPrice);
                if (map == null) {
                    wxCartCheckoutVo.setUserCouponId(-1);
                    wxCartCheckoutVo.setCouponId(-1);
                    couponPrice = BigDecimal.valueOf(0);
                } else {
                    wxCartCheckoutVo.setUserCouponId(map.get("userCouponId"));
                    couponId = map.get("couponId");
                    wxCartCheckoutVo.setCouponId(couponId);
                    couponPrice = marketCouponMapper.selectByPrimaryKey(couponId).getDiscount();
                }
            } else {
                wxCartCheckoutVo.setCouponId(couponId);
                wxCartCheckoutVo.setUserCouponId(userCouponId);
                couponPrice = marketCouponMapper.selectByPrimaryKey(couponId).getDiscount();
            }
        }
        wxCartCheckoutVo.setCouponPrice(couponPrice);
        BigDecimal actualPrice = goodsTotalPrice.add(freightPrice).subtract(couponPrice);
        if (actualPrice.compareTo(BigDecimal.ZERO) < 0) {
            actualPrice = BigDecimal.ZERO;
        }
        wxCartCheckoutVo.setActualPrice(actualPrice);
        //判断地址状态，addressId=0，查询该用户的默认收货地址；不为0查询当前地址
        wxCartCheckoutVo.setAddressId(addressId);
        MarketAddress marketAddress = null;
        if (addressId == 0) {
            MarketAddressExample marketAddressExample = new MarketAddressExample();
            marketAddressExample.createCriteria().andIsDefaultEqualTo(true);
            marketAddress = marketAddressMapper.selectOneByExampleSelective(marketAddressExample, MarketAddress.Column.id, MarketAddress.Column.name, MarketAddress.Column.userId,
                    MarketAddress.Column.province, MarketAddress.Column.city, MarketAddress.Column.county, MarketAddress.Column.addressDetail, MarketAddress.Column.areaCode,
                    MarketAddress.Column.tel, MarketAddress.Column.isDefault, MarketAddress.Column.addTime, MarketAddress.Column.updateTime, MarketAddress.Column.deleted);
        } else {
            marketAddress = marketAddressMapper.selectByPrimaryKeySelective(addressId, MarketAddress.Column.id, MarketAddress.Column.name, MarketAddress.Column.userId,
                    MarketAddress.Column.province, MarketAddress.Column.city, MarketAddress.Column.county, MarketAddress.Column.addressDetail, MarketAddress.Column.areaCode,
                    MarketAddress.Column.tel, MarketAddress.Column.isDefault, MarketAddress.Column.addTime, MarketAddress.Column.updateTime, MarketAddress.Column.deleted);
        }
        wxCartCheckoutVo.setCheckedAddress(marketAddress);
        return wxCartCheckoutVo;
    }

    //通过计算得出最省的优惠券，拿Id
    private Map<String, Integer> getDefaultCouponId(Integer userId, BigDecimal totalPrice) {
        List<MarketCouponUser> marketCouponUsers = getMarketCouponUserList(userId, totalPrice);
        if (marketCouponUsers.isEmpty()) return null;
        Integer couponId = -1;
        Integer userCouponId = -1;
        BigDecimal maxDiscount = BigDecimal.valueOf(0);
        for (MarketCouponUser marketCouponUser : marketCouponUsers) {
            Integer cid = marketCouponUser.getCouponId();
            MarketCoupon marketCoupon = marketCouponMapper.selectByPrimaryKey(cid);
            if (marketCoupon.getMin().compareTo(totalPrice) > 0) continue;
            BigDecimal discount = marketCoupon.getDiscount();
            if (maxDiscount.compareTo(discount) < 0) {
                maxDiscount = discount;
                couponId = cid;
                userCouponId = marketCouponUser.getId();
            }
        }
        HashMap<String, Integer> cidAndUcid = new HashMap<>();
        cidAndUcid.put("couponId", couponId);
        cidAndUcid.put("userCouponId", userCouponId);
        return cidAndUcid;
    }

    private List<MarketCouponUser> getMarketCouponUserList(Integer userId, BigDecimal totalPrice) {
        MarketCouponUserExample marketCouponUserExample = new MarketCouponUserExample();
        MarketCouponUserExample.Criteria conponCriteria = marketCouponUserExample.createCriteria();
        conponCriteria.andUserIdEqualTo(userId).andStartTimeLessThan(LocalDateTime.now()).andEndTimeGreaterThan(LocalDateTime.now()).andLogicalDeleted(true);
        List<MarketCouponUser> marketCouponUsers = marketCouponUserMapper.selectByExample(marketCouponUserExample);
        List<Integer> deleteIndex = new ArrayList<>();
        for (int i = 0; i < marketCouponUsers.size(); i++) {
            MarketCouponUser marketCouponUser = marketCouponUsers.get(i);
            MarketCoupon marketCoupon = marketCouponMapper.selectByPrimaryKey(marketCouponUser.getCouponId());
            if (marketCoupon.getMin().compareTo(totalPrice) > 0) {
                deleteIndex.add(i);
            }
        }
        // 从后向前删除
        for (int i = deleteIndex.size() - 1; i >= 0; i--) {
            marketCouponUsers.remove((int)deleteIndex.get(i));
        }
        return marketCouponUsers;
    }

    @Override
    public Map<String, Integer> fastadd(Integer goodsId, short number, Integer productId, Integer userId) {
        HashMap<String, Integer> attributeValueMap = new HashMap<>();
        BigDecimal price;
        MarketCartExample cartExample = new MarketCartExample();
        cartExample.createCriteria().andGoodsIdEqualTo(goodsId).andUserIdEqualTo(userId).andLogicalDeleted(true);
        MarketCart cart = marketCartMapper.selectOneByExample(cartExample);
        if (cart != null) {
            //已有该商品，更新数量
            MarketCart marketCart = new MarketCart();
            marketCart.setId(cart.getId());
            marketCart.setNumber(number);
            marketCart.setUpdateTime(LocalDateTime.now());
            price = marketGoodsProductMapper.selectByPrimaryKey(productId).getPrice();
            marketCart.setPrice(price);
            marketCart.setChecked(true);
            marketCartMapper.updateByPrimaryKeySelective(marketCart);
        } else {
            //写cart表
            MarketCart marketCart = new MarketCart();
            marketCart.setNumber(number);
            marketCart.setGoodsId(goodsId);
            marketCart.setProductId(productId);
            marketCart.setUserId(userId);
            marketCart.setChecked(true);
            marketCart.setSpecifications(marketGoodsProductMapper.selectByPrimaryKey(productId).getSpecifications());
            marketCart.setAddTime(LocalDateTime.now());
            marketCart.setUpdateTime(LocalDateTime.now());
            MarketGoods marketGoods = marketGoodsMapper.selectByPrimaryKey(goodsId);
            marketCart.setGoodsName(marketGoods.getName());
            marketCart.setGoodsSn(marketGoods.getGoodsSn());
            marketCart.setPicUrl(marketGoods.getPicUrl());
            price = marketGoodsProductMapper.selectByPrimaryKey(productId).getPrice();
            marketCart.setPrice(price);
            marketCartMapper.insertSelective(marketCart);
        }
        //读cart表拿id
        MarketCartExample marketCartExample = new MarketCartExample();
        marketCartExample.createCriteria().andUserIdEqualTo(userId).andGoodsIdEqualTo(goodsId).andNumberEqualTo(number).andProductIdEqualTo(productId);
        Integer cartId = marketCartMapper.selectOneByExample(marketCartExample).getId();
        attributeValueMap.put("cartId", cartId);
        //读address表拿默认地址id
        MarketAddressExample marketAddressExample = new MarketAddressExample();
        marketAddressExample.createCriteria().andIsDefaultEqualTo(true);
        Integer addressId = marketAddressMapper.selectOneByExample(marketAddressExample).getId();
        attributeValueMap.put("addressId", addressId);
        return attributeValueMap;
    }

    protected List<MarketCart> getCheckedCarts(List<MarketCart> marketCarts) {
        return marketCarts.stream()
                .filter(MarketCart::getChecked)
                .collect(Collectors.toList());
    }

    protected List<MarketCart> getMarketCarts(Integer userId) {
        MarketCartExample marketCartExample = new MarketCartExample();
        MarketCartExample.Criteria criteria = marketCartExample.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andLogicalDeleted(true);
        return marketCartMapper.selectByExampleSelective(marketCartExample, MarketCart.Column.id, MarketCart.Column.userId, MarketCart.Column.goodsId, MarketCart.Column.goodsSn,
                MarketCart.Column.goodsName, MarketCart.Column.productId, MarketCart.Column.price, MarketCart.Column.number, MarketCart.Column.specifications, MarketCart.Column.checked,
                MarketCart.Column.picUrl, MarketCart.Column.addTime, MarketCart.Column.updateTime, MarketCart.Column.deleted);
    }

    protected BigDecimal calculateTotalAmount(List<MarketCart> marketCarts) {
        return marketCarts.stream()
                .map(cart -> cart.getPrice().multiply(new BigDecimal(cart.getNumber())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    @Override
    public Integer getTotalCartGoods(Integer userId) {
        MarketCartExample marketCartExample = new MarketCartExample();
        MarketCartExample.Criteria criteria = marketCartExample.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andDeletedEqualTo(false);
        List<MarketCart> marketCarts = marketCartMapper.selectByExampleSelective(marketCartExample, MarketCart.Column.number);
        Integer data = 0;
        for (MarketCart marketCart : marketCarts) {
            data = marketCart.getNumber() + data;
        }
        return data;
    }

    @Transactional
    @Override
    public Integer addCart(Integer goodsId, Short number, Integer productId, Integer userId) {
        int data = 0;
        MarketCartExample marketCartExample = new MarketCartExample();
        MarketCartExample.Criteria criteria = marketCartExample.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andGoodsIdEqualTo(goodsId);
        criteria.andProductIdEqualTo(productId);
        criteria.andDeletedEqualTo(false);
        MarketCart marketCart = marketCartMapper.selectOneByExample(marketCartExample);
        if (marketCart != null) {
//            如果购物车之前有这条数据则更新
            marketCart.setUpdateTime(LocalDateTime.now());
            marketCart.setNumber((short) (marketCart.getNumber() + number));
            marketCartMapper.updateByPrimaryKeySelective(marketCart);
        } else {
            //去除已删除数据
            //如果购物车之前没有这件商品，则新增数据
            MarketGoodsExample marketGoodsExample = new MarketGoodsExample();
            MarketGoodsExample.Criteria goodsExampleCriteria = marketGoodsExample.createCriteria();
            goodsExampleCriteria.andDeletedEqualTo(false);
            goodsExampleCriteria.andIdEqualTo(goodsId);
            MarketGoods goods = marketGoodsMapper.selectOneByExampleSelective(marketGoodsExample, MarketGoods.Column.goodsSn, MarketGoods.Column.name, MarketGoods.Column.picUrl);
            MarketGoodsProductExample marketGoodsProductExample = new MarketGoodsProductExample();
            MarketGoodsProductExample.Criteria productExampleCriteria = marketGoodsProductExample.createCriteria();
            productExampleCriteria.andDeletedEqualTo(false);
            productExampleCriteria.andIdEqualTo(productId);
            MarketGoodsProduct product = marketGoodsProductMapper.selectOneByExampleSelective(marketGoodsProductExample, MarketGoodsProduct.Column.price, MarketGoodsProduct.Column.specifications);
            //需要根据goodsId获取goods表中的goodsSn，goodsName，product表中的price,specifications信息
            MarketCart cart = new MarketCart();
            cart.setAddTime(LocalDateTime.now());
            cart.setUpdateTime(LocalDateTime.now());
            cart.setNumber(number);
            cart.setProductId(productId);
            cart.setGoodsId(goodsId);
            cart.setUserId(userId);
            cart.setPicUrl(goods.getPicUrl());
            cart.setGoodsSn(goods.getGoodsSn());
            cart.setGoodsName(goods.getName());
            cart.setPicUrl(goods.getPicUrl());
            cart.setPrice(product.getPrice());
            cart.setSpecifications(product.getSpecifications());
            cart.setDeleted(false);
            marketCartMapper.insertSelective(cart);
        }
        data = getTotalCartGoods(userId);
        return data;
    }

    @Override
    public CartIndexVo index(Integer userId) {
        CartIndexVo data = new CartIndexVo();
        Map<String, Object> cartTotal = new HashMap<>();
        MarketCartExample marketCartExample = new MarketCartExample();
        MarketCartExample.Criteria criteria = marketCartExample.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andLogicalDeleted(true);
        List<MarketCart> marketCarts = marketCartMapper.selectByExample(marketCartExample);
        data.setCartList(marketCarts);
        BigDecimal checkedGoodsAmount = BigDecimal.ZERO;
        int checkedGoodsCount = 0;
        BigDecimal goodsAmount = BigDecimal.ZERO;
        int goodsCount = 0;
        for (MarketCart marketCart : marketCarts) {
            BigDecimal price = marketCart.getPrice();
            Short number = marketCart.getNumber();
            goodsAmount = goodsAmount.add(price.multiply(BigDecimal.valueOf(number)));
            goodsCount = goodsCount + number;
        }
        criteria.andCheckedEqualTo(true);
        List<MarketCart> checkedGoodsList = marketCartMapper.selectByExampleSelective(marketCartExample, MarketCart.Column.price, MarketCart.Column.number);
        for (MarketCart marketCart : checkedGoodsList) {
            BigDecimal price = marketCart.getPrice();
            Short number = marketCart.getNumber();
            checkedGoodsAmount = checkedGoodsAmount.add(price.multiply(BigDecimal.valueOf(number)));
            checkedGoodsCount = checkedGoodsCount + number;
        }
        cartTotal.put("checkedGoodsAmount", checkedGoodsAmount);
        cartTotal.put("checkedGoodsCount", checkedGoodsCount);
        cartTotal.put("goodsAmount", goodsAmount);
        cartTotal.put("goodsCount", goodsCount);
        data.setCartTotal(cartTotal);
        return data;
    }
}
